gtkmodelmenu: move to new action regime
authorRyan Lortie <desrt@desrt.ca>
Sat, 18 Aug 2012 03:13:42 +0000 (23:13 -0400)
committerRyan Lortie <desrt@desrt.ca>
Mon, 20 Aug 2012 17:13:49 +0000 (13:13 -0400)
Drop the explicit passing of GActionGroup into the GtkMenu(Bar)
constructors and operate from the action context instead.

With GtkMenuItem implementing GtkActionable, this turns out to be pretty
easy (and most of the code can be removed from GtkModelMenuItem,
including the GActionObserver implementation).

gtk/gtkapplicationwindow.c
gtk/gtkmodelmenu.c
gtk/gtkmodelmenu.h
gtk/gtkmodelmenuitem.c
gtk/gtkmodelmenuitem.h

index 7061309463f20794f57cea2f373f8b5e5765083b..b86920801f84b04ec6b1ee25dc8908fd6e673d75 100644 (file)
@@ -258,7 +258,7 @@ gtk_application_window_update_menubar (GtkApplicationWindow *window)
       g_menu_append_section (combined, NULL, G_MENU_MODEL (window->priv->app_menu_section));
       g_menu_append_section (combined, NULL, G_MENU_MODEL (window->priv->menubar_section));
 
-      window->priv->menubar = gtk_model_menu_create_menu_bar (G_MENU_MODEL (combined), window->priv->muxer, window->priv->accels);
+      window->priv->menubar = gtk_model_menu_create_menu_bar (G_MENU_MODEL (combined), window->priv->accels);
       gtk_widget_set_parent (window->priv->menubar, GTK_WIDGET (window));
       gtk_widget_show_all (window->priv->menubar);
       g_object_unref (combined);
index 9dd9aa5e468f3a427149639b2306627d25b26076..390923fdb46bf86d5ddffd7a27829303fe25c820 100644 (file)
@@ -32,7 +32,6 @@
 #define MODEL_MENU_WIDGET_DATA "gtk-model-menu-widget-data"
 
 typedef struct {
-  GActionObservable *actions;
   GMenuModel        *model;
   GtkAccelGroup     *accels;
   GtkMenuShell      *shell;
@@ -66,8 +65,6 @@ gtk_model_menu_binding_free (gpointer data)
       binding->connected = g_slist_delete_link (binding->connected, binding->connected);
     }
 
-  if (binding->actions)
-    g_object_unref (binding->actions);
   g_object_unref (binding->model);
 
   g_slice_free (GtkModelMenuBinding, binding);
@@ -85,12 +82,13 @@ gtk_model_menu_binding_append_item (GtkModelMenuBinding  *binding,
     {
       g_menu_model_get_item_attribute (model, item_index, "label", "s", heading);
       gtk_model_menu_binding_append_model (binding, section, FALSE);
+      g_object_unref (section);
     }
   else
     {
       GtkMenuItem *item;
 
-      item = gtk_model_menu_item_new (model, item_index, binding->actions, binding->accels);
+      item = gtk_model_menu_item_new (model, item_index, binding->accels);
       gtk_menu_shell_append (binding->shell, GTK_WIDGET (item));
       gtk_widget_show (GTK_WIDGET (item));
       binding->n_items++;
@@ -227,15 +225,14 @@ gtk_model_menu_binding_items_changed (GMenuModel *model,
 }
 
 static void
-gtk_model_menu_bind (GtkMenuShell      *shell,
-                     GMenuModel        *model,
-                     gboolean           with_separators)
+gtk_model_menu_bind (GtkMenuShell *shell,
+                     GMenuModel   *model,
+                     gboolean      with_separators)
 {
   GtkModelMenuBinding *binding;
 
   binding = g_slice_new (GtkModelMenuBinding);
   binding->model = g_object_ref (model);
-  binding->actions = NULL;
   binding->accels = NULL;
   binding->shell = shell;
   binding->update_idle = 0;
@@ -247,24 +244,21 @@ gtk_model_menu_bind (GtkMenuShell      *shell,
 
 
 static void
-gtk_model_menu_populate (GtkMenuShell      *shell,
-                         GActionObservable *actions,
-                         GtkAccelGroup     *accels)
+gtk_model_menu_populate (GtkMenuShell  *shell,
+                         GtkAccelGroup *accels)
 {
   GtkModelMenuBinding *binding;
 
   binding = (GtkModelMenuBinding*) g_object_get_data (G_OBJECT (shell), "gtk-model-menu-binding");
 
-  binding->actions = g_object_ref (actions);
   binding->accels = accels;
 
   gtk_model_menu_binding_populate (binding);
 }
 
 GtkWidget *
-gtk_model_menu_create_menu (GMenuModel        *model,
-                            GActionObservable *actions,
-                            GtkAccelGroup     *accels)
+gtk_model_menu_create_menu (GMenuModel    *model,
+                            GtkAccelGroup *accels)
 {
   GtkWidget *menu;
 
@@ -272,69 +266,11 @@ gtk_model_menu_create_menu (GMenuModel        *model,
   gtk_menu_set_accel_group (GTK_MENU (menu), accels);
 
   gtk_model_menu_bind (GTK_MENU_SHELL (menu), model, TRUE);
-  gtk_model_menu_populate (GTK_MENU_SHELL (menu), actions, accels);
+  gtk_model_menu_populate (GTK_MENU_SHELL (menu), accels);
 
   return menu;
 }
 
-static void
-gtk_model_menu_connect_app_window (GtkMenu *menu,
-                                   GtkApplicationWindow *window)
-{
-  GActionObservable *actions;
-  GtkAccelGroup *accels;
-
-  actions = gtk_application_window_get_observable (window);
-  accels = gtk_application_window_get_accel_group (window);
-
-  gtk_menu_set_accel_group (menu, accels);
-  gtk_model_menu_populate (GTK_MENU_SHELL (menu), actions, accels);
-}
-
-static void
-attach_widget_hierarchy_changed (GtkWidget *attach_widget,
-                                 GtkWidget *previous_toplevel,
-                                 gpointer user_data)
-{
-  GtkWidget *toplevel;
-  GtkMenu *menu = user_data;
-
-  toplevel = gtk_widget_get_toplevel (attach_widget);
-  if (GTK_IS_APPLICATION_WINDOW (toplevel))
-    gtk_model_menu_connect_app_window (menu, GTK_APPLICATION_WINDOW (toplevel));
-}
-
-static void
-notify_attach (GtkMenu    *menu,
-               GParamSpec *pspec,
-               gpointer    data)
-{
-  GtkWidget *attach_widget, *toplevel;
-
-  attach_widget = g_object_get_data (G_OBJECT (menu), MODEL_MENU_WIDGET_DATA);
-  if (attach_widget != NULL)
-    {
-      g_signal_handlers_disconnect_by_func (attach_widget, attach_widget_hierarchy_changed, menu);
-      g_object_set_data (G_OBJECT (menu), MODEL_MENU_WIDGET_DATA, NULL);
-    }
-
-  attach_widget = gtk_menu_get_attach_widget (menu);
-  if (!attach_widget)
-    return;
-
-  toplevel = gtk_widget_get_toplevel (attach_widget);
-  if (GTK_IS_APPLICATION_WINDOW (toplevel))
-    {
-      gtk_model_menu_connect_app_window (menu, GTK_APPLICATION_WINDOW (toplevel));
-    }
-  else
-    {
-      g_object_set_data (G_OBJECT (menu), MODEL_MENU_WIDGET_DATA, attach_widget);
-      g_signal_connect_object (attach_widget, "hierarchy-changed",
-                               G_CALLBACK (attach_widget_hierarchy_changed), menu, 0);
-    }
-}
-
 /**
  * gtk_menu_new_from_model:
  * @model: a #GMenuModel
@@ -358,46 +294,25 @@ gtk_menu_new_from_model (GMenuModel *model)
 
   menu = gtk_menu_new ();
   gtk_model_menu_bind (GTK_MENU_SHELL (menu), model, TRUE);
-  g_signal_connect (menu, "notify::attach-widget",
-                    G_CALLBACK (notify_attach), NULL);
+  gtk_model_menu_populate (GTK_MENU_SHELL (menu), NULL);
 
   return menu;
 }
 
 GtkWidget *
-gtk_model_menu_create_menu_bar (GMenuModel        *model,
-                                GActionObservable *actions,
-                                GtkAccelGroup     *accels)
+gtk_model_menu_create_menu_bar (GMenuModel    *model,
+                                GtkAccelGroup *accels)
 {
   GtkWidget *menubar;
 
   menubar = gtk_menu_bar_new ();
 
   gtk_model_menu_bind (GTK_MENU_SHELL (menubar), model, FALSE);
-  gtk_model_menu_populate (GTK_MENU_SHELL (menubar), actions, accels);
+  gtk_model_menu_populate (GTK_MENU_SHELL (menubar), accels);
 
   return menubar;
 }
 
-static void
-hierarchy_changed (GtkMenuShell *shell,
-                   GObject      *previous_toplevel,
-                   gpointer      data)
-{
-  GtkWidget *toplevel;
-  GActionObservable *actions;
-  GtkAccelGroup *accels;
-
-  toplevel = gtk_widget_get_toplevel (GTK_WIDGET (shell));
-  if (GTK_IS_APPLICATION_WINDOW (toplevel))
-    {
-      actions = gtk_application_window_get_observable (GTK_APPLICATION_WINDOW (toplevel));
-      accels = gtk_application_window_get_accel_group (GTK_APPLICATION_WINDOW (toplevel));
-
-      gtk_model_menu_populate (shell, actions, accels);
-    }
-}
-
 /**
  * gtk_menu_bar_new_from_model:
  * @model: a #GMenuModel
@@ -422,9 +337,7 @@ gtk_menu_bar_new_from_model (GMenuModel *model)
   menubar = gtk_menu_bar_new ();
 
   gtk_model_menu_bind (GTK_MENU_SHELL (menubar), model, FALSE);
-
-  g_signal_connect (menubar, "hierarchy-changed",
-                    G_CALLBACK (hierarchy_changed), NULL);
+  gtk_model_menu_populate (GTK_MENU_SHELL (menubar), NULL);
 
   return menubar;
 }
index d2df78fbc583c37d9657bfcedca6ce910831109d..05654c959e059ab587ba8117e6e69dd80481f15b 100644 (file)
 #ifndef __GTK_MODEL_MENU_H__
 #define __GTK_MODEL_MENU_H__
 
-#include <gtk/gactionobservable.h>
 #include <gtk/gtkmenushell.h>
 #include <gtk/gtkaccelgroup.h>
 #include <gio/gio.h>
 
 G_GNUC_INTERNAL
 GtkWidget * gtk_model_menu_create_menu_bar (GMenuModel        *model,
-                                            GActionObservable *actions,
                                             GtkAccelGroup     *accels);
 
 G_GNUC_INTERNAL
 GtkWidget * gtk_model_menu_create_menu     (GMenuModel        *model,
-                                            GActionObservable *actions,
                                             GtkAccelGroup     *accels);
 
 #endif /* __GTK_MODEL_MENU_H__ */
index d07f4d258447c2e8bc93303a61cc086ad09764ea..07cad7093c88dc02e20df6d7d739c3b6c7f89c04 100644 (file)
 #include "gtkmodelmenuitem.h"
 
 #include "gtkaccelmapprivate.h"
+#include "gtkactionhelper.h"
 #include "gtkmodelmenu.h"
 
 struct _GtkModelMenuItem
 {
   GtkCheckMenuItem parent_instance;
-
-  GActionGroup *actions;
-  const gchar *action_name;
+  GtkActionHelperRole role;
   gboolean has_indicator;
-  gboolean can_activate;
-  GVariant *target;
 };
 
 typedef GtkCheckMenuItemClass GtkModelMenuItemClass;
 
-static void gtk_model_menu_item_observer_iface_init (GActionObserverInterface *iface);
-G_DEFINE_TYPE_WITH_CODE (GtkModelMenuItem, gtk_model_menu_item, GTK_TYPE_CHECK_MENU_ITEM,
-                         G_IMPLEMENT_INTERFACE (G_TYPE_ACTION_OBSERVER, gtk_model_menu_item_observer_iface_init))
+G_DEFINE_TYPE (GtkModelMenuItem, gtk_model_menu_item, GTK_TYPE_CHECK_MENU_ITEM)
 
-static void
-gtk_model_menu_item_activate (GtkMenuItem *menu_item)
-{
-  GtkModelMenuItem *item = GTK_MODEL_MENU_ITEM (menu_item);
-
-  if (item->can_activate)
-    g_action_group_activate_action (item->actions, item->action_name, item->target);
-}
+#define PROP_ACTION_ROLE 1
 
 static void
 gtk_model_menu_item_toggle_size_request (GtkMenuItem *menu_item,
@@ -75,123 +63,10 @@ gtk_model_menu_item_draw_indicator (GtkCheckMenuItem *check_item,
       ->draw_indicator (check_item, cr);
 }
 
-static void
-gtk_model_menu_item_set_active (GtkModelMenuItem *item,
-                                gboolean          active)
-{
-  GtkCheckMenuItem *checkitem = GTK_CHECK_MENU_ITEM (item);
-
-  if (gtk_check_menu_item_get_active (checkitem) != active)
-    {
-      _gtk_check_menu_item_set_active (checkitem, active);
-      g_object_notify (G_OBJECT (checkitem), "active");
-      gtk_check_menu_item_toggled (checkitem);
-      gtk_widget_queue_draw (GTK_WIDGET (item));
-    }
-}
-
-static void
-gtk_model_menu_item_action_added (GActionObserver    *observer,
-                                  GActionObservable  *observable,
-                                  const gchar        *action_name,
-                                  const GVariantType *parameter_type,
-                                  gboolean            enabled,
-                                  GVariant           *state)
-{
-  GtkModelMenuItem *item = GTK_MODEL_MENU_ITEM (observer);
-
-  /* we can only activate the item if we have the correct type of parameter */
-  item->can_activate = (item->target == NULL && parameter_type == NULL) ||
-                       (item->target != NULL && parameter_type != NULL &&
-                        g_variant_is_of_type (item->target, parameter_type));
-
-  if (item->can_activate)
-    {
-      if (item->target != NULL && state != NULL)
-        {
-          /* actions with states and targets are radios */
-          gboolean selected;
-
-          selected = g_variant_equal (state, item->target);
-          gtk_check_menu_item_set_draw_as_radio (GTK_CHECK_MENU_ITEM (item), TRUE);
-          gtk_model_menu_item_set_active (item, selected);
-          item->has_indicator = TRUE;
-        }
-
-      else if (state != NULL && g_variant_is_of_type (state, G_VARIANT_TYPE_BOOLEAN))
-        {
-          /* boolean state actions without target are checks */
-          gtk_check_menu_item_set_draw_as_radio (GTK_CHECK_MENU_ITEM (item), FALSE);
-          gtk_model_menu_item_set_active (item, g_variant_get_boolean (state));
-          item->has_indicator = TRUE;
-        }
-
-      else
-        {
-          /* stateless items are just plain actions */
-          gtk_model_menu_item_set_active (item, FALSE);
-          item->has_indicator = FALSE;
-        }
-
-      gtk_widget_set_sensitive (GTK_WIDGET (item), enabled);
-      gtk_widget_queue_resize (GTK_WIDGET (item));
-    }
-}
-
-static void
-gtk_model_menu_item_action_enabled_changed (GActionObserver   *observer,
-                                            GActionObservable *observable,
-                                            const gchar       *action_name,
-                                            gboolean           enabled)
-{
-  GtkModelMenuItem *item = GTK_MODEL_MENU_ITEM (observer);
-
-  if (!item->can_activate)
-    return;
-
-  gtk_widget_set_sensitive (GTK_WIDGET (item), item->can_activate && enabled);
-}
-
-static void
-gtk_model_menu_item_action_state_changed (GActionObserver   *observer,
-                                          GActionObservable *observable,
-                                          const gchar       *action_name,
-                                          GVariant          *state)
-{
-  GtkModelMenuItem *item = GTK_MODEL_MENU_ITEM (observer);
-
-  if (!item->can_activate)
-    return;
-
-  if (item->target)
-    gtk_model_menu_item_set_active (item, g_variant_equal (state, item->target));
-
-  else if (g_variant_is_of_type (state, G_VARIANT_TYPE_BOOLEAN))
-    gtk_model_menu_item_set_active (item, g_variant_get_boolean (state));
-}
-
-static void
-gtk_model_menu_item_action_removed (GActionObserver   *observer,
-                                    GActionObservable *observable,
-                                    const gchar       *action_name)
-{
-  GtkModelMenuItem *item = GTK_MODEL_MENU_ITEM (observer);
-
-  if (!item->can_activate)
-    return;
-
-  gtk_widget_set_sensitive (GTK_WIDGET (item), FALSE);
-  gtk_model_menu_item_set_active (item, FALSE);
-  item->has_indicator = FALSE;
-
-  gtk_widget_queue_resize (GTK_WIDGET (item));
-}
-
 static void
 gtk_model_menu_item_setup (GtkModelMenuItem  *item,
                            GMenuModel        *model,
                            gint               item_index,
-                           GActionObservable *actions,
                            GtkAccelGroup     *accels)
 {
   GMenuAttributeIter *iter;
@@ -201,7 +76,7 @@ gtk_model_menu_item_setup (GtkModelMenuItem  *item,
 
   if ((submenu = g_menu_model_get_item_link (model, item_index, "submenu")))
     {
-      gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), gtk_model_menu_create_menu (submenu, actions, accels));
+      gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), gtk_model_menu_create_menu (submenu, accels));
       g_object_unref (submenu);
     }
 
@@ -212,68 +87,74 @@ gtk_model_menu_item_setup (GtkModelMenuItem  *item,
         gtk_menu_item_set_label (GTK_MENU_ITEM (item), g_variant_get_string (value, NULL));
 
       else if (g_str_equal (key, "action") && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING))
-        item->action_name = g_variant_get_string (value, NULL);
+        gtk_actionable_set_action_name (GTK_ACTIONABLE (item), g_variant_get_string (value, NULL));
 
       else if (g_str_equal (key, "target"))
-        item->target = g_variant_ref (value);
+        gtk_actionable_set_action_target_value (GTK_ACTIONABLE (item), value);
 
       g_variant_unref (value);
     }
   g_object_unref (iter);
 
   gtk_menu_item_set_use_underline (GTK_MENU_ITEM (item), TRUE);
-
-  if (item->action_name)
-    {
-      const GVariantType *type;
-      gboolean enabled;
-      GVariant *state;
-      gchar *path;
-
-      /* observer already causes us to hold a hard ref on the group */
-      item->actions = G_ACTION_GROUP (actions);
-
-      if (actions)
-        {
-          g_action_observable_register_observer (actions, item->action_name, G_ACTION_OBSERVER (item));
-
-          if (g_action_group_query_action (G_ACTION_GROUP (actions), item->action_name, &enabled, &type, NULL, NULL, &state))
-            {
-              gtk_model_menu_item_action_added (G_ACTION_OBSERVER (item), actions, item->action_name, type, enabled, state);
-              if (state != NULL)
-                g_variant_unref (state);
-            }
-          else
-            gtk_widget_set_sensitive (GTK_WIDGET (item), FALSE);
-        }
-      else
-        gtk_widget_set_sensitive (GTK_WIDGET (item), FALSE);
-
-      path = _gtk_accel_path_for_action (item->action_name, item->target);
-      gtk_menu_item_set_accel_path (GTK_MENU_ITEM (item), path);
-      g_free (path);
-    }
 }
 
 static void
-gtk_model_menu_item_finalize (GObject *object)
+gtk_model_menu_item_set_has_indicator (GtkModelMenuItem *item,
+                                       gboolean          has_indicator)
 {
-  G_OBJECT_CLASS (gtk_model_menu_item_parent_class)
-    ->finalize (object);
+  if (has_indicator == item->has_indicator)
+    return;
+
+  item->has_indicator = has_indicator;
+
+  gtk_widget_queue_resize (GTK_WIDGET (item));
 }
 
 static void
-gtk_model_menu_item_init (GtkModelMenuItem *item)
+gtk_model_menu_item_set_property (GObject *object, guint prop_id,
+                                  const GValue *value, GParamSpec *pspec)
 {
+  GtkModelMenuItem *item = GTK_MODEL_MENU_ITEM (object);
+  GtkActionHelperRole role;
+  AtkObject *accessible;
+  AtkRole a11y_role;
+
+  g_assert (prop_id == PROP_ACTION_ROLE);
+
+  role = g_value_get_uint (value);
+
+  if (role == item->role)
+    return;
+
+  gtk_check_menu_item_set_draw_as_radio (GTK_CHECK_MENU_ITEM (item), role == GTK_ACTION_HELPER_ROLE_RADIO);
+  gtk_model_menu_item_set_has_indicator (item, role != GTK_ACTION_HELPER_ROLE_NORMAL);
+
+  accessible = gtk_widget_get_accessible (GTK_WIDGET (item));
+  switch (role)
+    {
+    case GTK_ACTION_HELPER_ROLE_NORMAL:
+      a11y_role = ATK_ROLE_MENU_ITEM;
+      break;
+
+    case GTK_ACTION_HELPER_ROLE_TOGGLE:
+      a11y_role = ATK_ROLE_CHECK_MENU_ITEM;
+      break;
+
+    case GTK_ACTION_HELPER_ROLE_RADIO:
+      a11y_role = ATK_ROLE_RADIO_MENU_ITEM;
+      break;
+
+    default:
+      g_assert_not_reached ();
+    }
+
+  atk_object_set_role (accessible, a11y_role);
 }
 
 static void
-gtk_model_menu_item_observer_iface_init (GActionObserverInterface *iface)
+gtk_model_menu_item_init (GtkModelMenuItem *item)
 {
-  iface->action_added = gtk_model_menu_item_action_added;
-  iface->action_enabled_changed = gtk_model_menu_item_action_enabled_changed;
-  iface->action_state_changed = gtk_model_menu_item_action_state_changed;
-  iface->action_removed = gtk_model_menu_item_action_removed;
 }
 
 static void
@@ -285,23 +166,25 @@ gtk_model_menu_item_class_init (GtkModelMenuItemClass *class)
 
   check_class->draw_indicator = gtk_model_menu_item_draw_indicator;
 
-  item_class->activate = gtk_model_menu_item_activate;
   item_class->toggle_size_request = gtk_model_menu_item_toggle_size_request;
 
-  object_class->finalize = gtk_model_menu_item_finalize;
+  object_class->set_property = gtk_model_menu_item_set_property;
+
+  g_object_class_install_property (object_class, PROP_ACTION_ROLE,
+                                   g_param_spec_uint ("action-role", "action role", "action role",
+                                                      0, 2, 0, G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
 }
 
 GtkMenuItem *
 gtk_model_menu_item_new (GMenuModel        *model,
                          gint               item_index,
-                         GActionObservable *actions,
                          GtkAccelGroup     *accels)
 {
   GtkModelMenuItem *item;
 
   item = g_object_new (GTK_TYPE_MODEL_MENU_ITEM, NULL);
 
-  gtk_model_menu_item_setup (item, model, item_index, actions, accels);
+  gtk_model_menu_item_setup (item, model, item_index, accels);
 
   return GTK_MENU_ITEM (item);
 }
index c12990041985adf81dd9d66c3c8bf309314d9d9b..8017e3baf00637b5976c24ac2ce4dc891b3c4f33 100644 (file)
@@ -20,7 +20,6 @@
 #ifndef __GTK_MODEL_MENU_ITEM_H__
 #define __GTK_MODEL_MENU_ITEM_H__
 
-#include <gtk/gactionobservable.h>
 #include <gtk/gtkcheckmenuitem.h>
 
 #define GTK_TYPE_MODEL_MENU_ITEM                            (gtk_model_menu_item_get_type ())
@@ -37,7 +36,6 @@ GType                   gtk_model_menu_item_get_type                    (void) G
 G_GNUC_INTERNAL
 GtkMenuItem *           gtk_model_menu_item_new                         (GMenuModel        *model,
                                                                          gint               item_index,
-                                                                         GActionObservable *actions,
                                                                          GtkAccelGroup     *accels);
 
 #endif /* __GTK_MODEL_MENU_ITEM_H__ */